package junk;
import java.awt.geom.Point2D;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;

import jsc.distributions.Hypergeometric;

import processing.core.PApplet;

class Protein extends MoveObject{
	public static Protein[] proteinList;
	public static int position;
	public static int position2;
	public static boolean proteinsInCenter = false;
	public static String lastProteinGroup;
	public static boolean drawLines = true;
	public static Protein allProteins;
		
	public static void drawProteins() {
		position = 0;
		position2 = 0;
		for (int i = 0; i< proteinList.length; i++)
        {
        	if(proteinList[i].showMe) proteinList[i].drawMe(false);
        }
	}
	public static void findProteins() {
		position = 0;
		for (int i = 0; i< proteinList.length; i++)
        {
			if(Main1.loop && Main1.activeItem instanceof Protein)
        	{
        		Protein p = (Protein) Main1.activeItem;
        		p.x1 = p.parent.mouseX - p.parent.width/2 + Main1.xTranslate;
        		p.y1 = p.parent.mouseY - p.parent.height/2;
        		p.isSet = true;
        		if(Math.sqrt((double)(p.x1*p.x1 + p.y1*p.y1)) > Main1.outerRadius)
        			if(p.type.equals("Group"))
        			{
        					Main1.showProteins = "None";
        					proteinList[i].setCoordinates( proteinList.length);
        			}
        			else p.showBinding = false;
        		else
        			if(p.type.equals("Group"))
        			{
        					Main1.showProteins = p.name;
        					proteinList[i].setCoordinates( proteinList.length);
        					while(!Main1.proteinGroups[Main1.proteinGroup].equals(p.name))  Main1.proteinGroup = (Main1.proteinGroup + 1) % (Main1.proteinGroupsSize.length);
        			}
        			else p.showBinding = true;
        		p.x1 = p.parent.mouseX - p.parent.width/2 + Main1.xTranslate;
        		p.y1 = p.parent.mouseY - p.parent.height/2;
        	}
			else if(!Main1.loop && !Main1.showProteins.equals(lastProteinGroup) || Main1.resized) 
        		proteinList[i].setCoordinates( proteinList.length);
        }
		if(!Main1.showProteins.equals(lastProteinGroup))
			lastProteinGroup = Main1.showProteins;
	}
	
	public PApplet parent;
	public String name;
	public String type;
	public String annotation;
	public String set;
	public double x;
	public double y;
	public float x1, y1 ,width, height;
	public int numInGroup;
	public int columnInData;
	public boolean isSelected;
	public boolean isActiveItem;
	public boolean showMe;
	public boolean setPosition;
	public boolean showBinding;
	public boolean isSet;
	public boolean showEnrichment = true;
	public boolean expand;
	public int myOpacity = 90;
	//public Annotations[] groupHeigherarchy;
	public ArrayList<Protein> children;
	public Protein parentProtein;
	public int tablePosition;

	
	
	public Protein( String t, String n, String ann, int num, PApplet p)
	{
		super(p);
		name = n;
		columnInData = num;
		annotation = ann;
		parent = p;
		type = t;
		set  = "";
		showMe = false;
		isSelected = false;
		isActiveItem = false;
		showBinding = true;
		isSet = false;
	}
	public Protein( String t, String n, String ann, String s, int num, PApplet p)
	{
		super(p);
		name = n;
		columnInData = num;
		annotation = ann;
		parent = p;
		type = t;
		set = s;
		showMe = false;
		isSelected = false;
		isActiveItem = false;
		showBinding = true;
		isSet = false;
	}
	public Protein( String t, String n, String ann, PApplet p)
	{
		super(p);
		name = n;
		parent = p;
		type = t;
		annotation = ann;
		set = "";
		showMe = false;
		isSelected = false;
		isActiveItem = false;
		showBinding = false;
		isSet = false;
		children = new ArrayList<Protein>();
	}
	public Protein( String t, PApplet p)
	{
		super(p);
		parent = p;
		type = t;
		annotation = t;
		set = "";
		showMe = false;
		isSelected = false;
		isActiveItem = false;
		showBinding = false;
		isSet = false;
		children = new ArrayList<Protein>();
	}
	public void setCoordinates( int numProteins)
	{
		int numDisplayed;
		showMe = false;
		if (type.equals("Group"))
		{
			x1 = parent.width*.7f;
			y1 = parent.height*.9f;
			
			//showMe = true;
			showMe = false;
			showBinding = false;
			position2 = position2 + 1;
		}
		else if (annotation.equals(Main1.showProteins)  && !isSet)
		{			
			position = position + 1;	
			showMe = true;
			
			numDisplayed = Main1.proteinGroupsSize[Main1.proteinGroup];
		
			float radius;
			if(proteinsInCenter)
				radius = parent.width*.35f;
			else 
				radius = Main1.innerRadius;
			
			if(proteinsInCenter)
			{
				if(numDisplayed > 1) this.y = ((float)(position-1)/(float)(numDisplayed-1))*2f - 1;
				else this.y = 0;
				this.x = 0;
			}
			else
			{
				this.x = Math.cos(((Math.PI- Main1.angleOffset*2)*((float)position-.5)/ (float)numDisplayed)+(3*Math.PI/2+Main1.angleOffset));
				this.y = Math.sin(((Math.PI- Main1.angleOffset*2)*((float)position-.5)/ (float)numDisplayed)+(3*Math.PI/2+Main1.angleOffset));
			}
			x1 = (float) (x*radius);
			y1 = (float) (-y*radius);
			showBinding = true;
		}
		if( isSet) 
		{
			showMe = true;
			if(type.equals("Group") && Main1.showProteins != name && Main1.activeItem != this) showMe = false;
			if(annotation.equals(Main1.showProteins)) position = position + 1;	
		}
 		if(numInGroup == 0) numInGroup = position;
	}
	public void drawMe( boolean findMouse ) {
		parent.rectMode(Main1.CENTER);
		if(drawLines == true) drawLines();
		String display;
		if(Main1.showProteins.equals("Groups")) display = annotation;
		else display = name;
		width = parent.width*.05f;
		height =parent.width*.02f;
		int color;
		if(type.equals("Group")) 
		{
			if (isSelected) color = parent.color(50,237,232);
			else color = parent.color(50,237,232,100);
			if(Main1.lighter) parent.fill(Main1.blendColor(parent.color(255),parent.color(color), Main1.SUBTRACT));
			else parent.fill(color);
			color = parent.color(27,113,111);
			if(Main1.lighter) parent.stroke(Main1.blendColor(parent.color(255),parent.color(color), Main1.SUBTRACT));
			else parent.stroke(color);
			parent.strokeWeight(5);
			((Main1) parent).roundRect(x1-(width*.75f),y1-(height*.75f),width*1.5f,height*1.5f);
			parent.textFont(Main1.font14);
			if (isSelected) color = parent.color(87,100,12);
			else color = parent.color(212,240,123);
			if(Main1.lighter) parent.fill(Main1.blendColor(parent.color(255),parent.color(color), Main1.SUBTRACT));
			else parent.fill(color);
			parent.textAlign(Main1.CENTER);
			parent.text(display, x1, y1);
		}
		else
		{
			if (isSelected) color = parent.color(108,198,90);
			else color = parent.color(108,198,90,100);
			if(Main1.lighter) parent.fill(Main1.blendColor(parent.color(255),parent.color(color), Main1.SUBTRACT));
			else parent.fill(color);
			color = parent.color(26,93,13);
			if(Main1.lighter) parent.stroke(Main1.blendColor(parent.color(255),parent.color(color), Main1.SUBTRACT));
			else parent.stroke(color);
			parent.strokeWeight(5);
			parent.ellipse(x1,y1,width,height);
			parent.textFont(Main1.font10);
			if (!isSelected) color = parent.color(234,234,178);
			else color = parent.color(93,93,32);
			if(Main1.lighter) parent.fill(Main1.blendColor(parent.color(255),parent.color(color), Main1.SUBTRACT));
			else parent.fill(color);
			parent.textAlign(Main1.CENTER);
			parent.text(display, x1, y1);
		}
		parent.strokeWeight(1);
		parent.textAlign(Main1.LEFT);
	}
	public void checkMouseOver()
	{
		if((parent.mouseX-parent.width/2 + Main1.xTranslate) > (x1- width/2) && (parent.mouseX-parent.width/2 + Main1.xTranslate) < (x1 + width/2))
			if((parent.mouseY-parent.height/2) > (y1- height/2) && (parent.mouseY-parent.height/2) < (y1 + height/2))
			{
				isSelected = !isSelected;
				if(Main1.activeItem instanceof Protein) 
				{
					Protein p = (Protein) Main1.activeItem;
					if(p != null) p.isActiveItem = false;
				}
				Main1.activeItem = this;
				isActiveItem = true;
				parent.redraw();
			}
	}
	public boolean isMouseOver()
	{
		int mX = parent.mouseX;
		int mY = parent.mouseY;
		int xT = Main1.xTranslate;
		if((mX-parent.width/2 + xT) > (x1- width/2) && (mX-parent.width/2 + xT) < (x1 + width/2))
			if((mY-parent.height/2) > (y1- height/2) && (mY-parent.height/2) < (y1 + height/2))		
				return true;
		return false;
	}
	public String toString()
	{
		return name;
	}
	public void unSelect()
	{
		isActiveItem = false;
	}
	public void drawLines()
	{
		Gene[] geneList = Main1.firstAnnotation.genes;
		int radius  = (int)(Main1.innerRadius*.99);
		double pValueCutoff = Main1.pValueCutoff;
		double expressionCutoff = Main1.expressionCutoff;
		int[] markedItemCount = {0,0};
		int[][] annotationCounts = new int[Main1.firstAnnotation.children.length][2];
		for(int[] i: annotationCounts)
			for(int j: i) j = 0;
	
		for (int i = 0; i< geneList.length; i++)
		{
			int j  = columnInData;
			{
				boolean drawLine = false;				
				boolean isPositive = false;
				
				for(int z = 0; z< ReadGenes.datasets.length; z++)
				{
					if(set.equals(ReadGenes.datasets[z]))
					{
						if(type.equals("Raw"))
						{
								drawLine = Math.pow(geneList[i].expressionConditions.get(z)[j],2) > expressionCutoff;
								isPositive = geneList[i].expressionConditions.get(z)[j] > 0;								
						}
						else 
						{
							drawLine = geneList[i].expressionConditions.get(z)[j] < pValueCutoff;
						}
					}
				}
				
					
				if (drawLine)
				{	
					Gene gene = Main1.firstAnnotation.genes[i];
					if(showEnrichment && !isSelected)
					{
						if(isPositive)
							markedItemCount[0] = markedItemCount[0] +1;
						else
							markedItemCount[1] = markedItemCount[1] +1;
						for(int z = 0; z<Main1.firstAnnotation.children.length; z++)
						{
							if( gene.groupHeigherarchy[0].groupName.equals(Main1.firstAnnotation.children[z].groupName))
							{
								if(isPositive)
									annotationCounts[z][0] = annotationCounts[z][0] + 1;
								else
									annotationCounts[z][1] = annotationCounts[z][1] + 1;
							}
						}
						
					}
					else
					{
						int idx  = gene.numAnnotations - 1;
			    		float c1X = gene.groupHeigherarchy[0].centerX;
			    		float c1Y = -gene.groupHeigherarchy[0].centerY;
			    		float c2X = 0;
			    		float c2Y = 0;
			    		if(idx >1)
			    		{
			    			c2X = gene.groupHeigherarchy[1].centerX;
			    			c2Y = -gene.groupHeigherarchy[1].centerY;
			    		}
			    		float geneX, geneY;
			    		if(gene.active)
			    		{
			    			geneX = (float) gene.x*radius;
			    			geneY = (float)-gene.y*radius;
			    		}
			    		else
			    		{
			    			geneX = gene.activeAnnotation.midX;
			    			geneY = gene.activeAnnotation.midY;
			    		}
			    		if(!isSelected) parent.stroke(128,25);
			    		else parent.stroke(proteinColor(numInGroup, myOpacity));
			    		parent.noFill();    
			    		//if(showMe && showBinding)
			    		if (false && showMe && showBinding)
			    		{
			    			if(idx > 1) parent.bezier(geneX, geneY,c1X, c1Y, c2X, c2Y, x1, y1);
			    			else parent.bezier(geneX, geneY, c1X, c1Y, 0, 0, x1, y1);
			    		}
			    		else
			    		{
				    		Point2D.Float[] pts = new Point2D.Float[8];
				    		pts[0] = new Point2D.Float((float)gene.x*radius, (float)-gene.y*radius);
				    		pts[1] = new Point2D.Float((float)gene.x*radius, (float)-gene.y*radius);
				    		pts[2] = new Point2D.Float((float)gene.x*radius, (float)-gene.y*radius);
				    		pts[3] = new Point2D.Float(c1X, c1Y);
				    		pts[4] = new Point2D.Float(c2X, c2Y);
				    		pts[5] = new Point2D.Float(x1, y1);
				    		pts[6] = new Point2D.Float(x1, y1);
				    		pts[7] = new Point2D.Float(x1, y1);
				    		
				    		float b = (float)Main1.bundlingStrength;
				    		for( int k= 2; k< 6; k++)
				    		{
				    			pts[k].x = pts[k].x*b + (1-b)*(pts[0].x + ((k-2)/3)*(pts[7].x-pts[0].x));
				    			pts[k].y = pts[k].y*b + (1-b)*(pts[0].y + ((k-2)/3)*(pts[7].y-pts[0].y));
				    		}
				    		pts[0] = pts[1] = pts[2];
				    		pts[7] = pts[6] = pts[5];
				    			
				    		if(showMe && showBinding) bSpline(pts);
			    		}
		    		}
		    		
		    	}
			}
		}
		if(showEnrichment &&  showMe && showBinding && !isSelected)
		{
			for(int z = 0; z<Main1.firstAnnotation.children.length; z++)
			{
				if(Main1.firstAnnotation.children[z].genes.length > 0)
				{
					Hypergeometric h;
					if(markedItemCount[1] > 0 && Main1.firstAnnotation.children[z].genes.length >0 && Main1.firstAnnotation.children[z].genes.length != Main1.firstAnnotation.genes.length)
					{
						try
						{
							h = new Hypergeometric(Main1.firstAnnotation.children[z].genes.length, Main1.firstAnnotation.genes.length,markedItemCount[1]);
							double temp = 0;
							for (int i = annotationCounts[z][1]; i< (int)Math.min(h.getSampleSize(), h.getMarkedItemsCount()); i++)
								temp = temp + h.pdf(i);
							int color= parent.color(0,255,0,128);
							if(Main1.lighter) parent.stroke(Main1.blendColor(parent.color(255),parent.color(color), Main1.SUBTRACT));
							else parent.stroke(color);
							if(temp< .01) 
							{
								parent.strokeWeight((float)(Math.sqrt(-Math.log(temp))));
								parent.line(Main1.firstAnnotation.children[z].midX, Main1.firstAnnotation.children[z].midY, x1, y1);
							}
						}
						catch (Exception e)
						{
							
						}
					}
					if(markedItemCount[0] > 0 && Main1.firstAnnotation.children[z].genes.length >0  && Main1.firstAnnotation.children[z].genes.length != Main1.firstAnnotation.genes.length) 
					{
						try
						{
							h = new Hypergeometric(Main1.firstAnnotation.children[z].genes.length, Main1.firstAnnotation.genes.length,markedItemCount[0]);
							double temp = 0;
							for (int i = annotationCounts[z][0]; i< (int)Math.min(h.getSampleSize(), h.getMarkedItemsCount()); i++)
								temp = temp + h.pdf(i);
							int color = parent.color(255,0,0,128);					
							if(Main1.lighter) parent.stroke(Main1.blendColor(parent.color(255),parent.color(color), Main1.SUBTRACT));
							else parent.stroke(color);
							if(temp< .01) 
							{
								parent.strokeWeight((float)(Math.sqrt(-Math.log(temp))));
								parent.line(Main1.firstAnnotation.children[z].midX, Main1.firstAnnotation.children[z].midY, x1, y1);
							}
						}
						catch (Exception e)
						{
							
						}
					}
				}
			}
		}
	}
	private void bSpline(Point2D.Float[] pts)
	{
		parent.noFill();
		final int STEPS = 12;

		parent.beginShape();
	    Point2D.Float q = p(2,0,pts);
		parent.vertex(q.x, q.y);
		for (int i = 2; i < pts.length-1; i++) {
		  for (int j = 1; j <= STEPS; j++) {
			  q = p(i,j/(float)STEPS, pts);
			  parent.vertex(q.x,q.y);
		  }
		}
		parent.endShape();
	}
	// the basis function for a cubic B spline
	  float b(int i, float t) {
	    switch (i) {
	    case -2:
	      return (((-t+3)*t-3)*t+1)/6;
	    case -1:
	      return (((3*t-6)*t)*t+4)/6;
	    case 0:
	      return (((-3*t+3)*t+3)*t+1)/6;
	    case 1:
	      return (t*t*t)/6;
	    }
	    return 0; //we only get here if an invalid i is specified
	  }
	  
	  //evaluate a point on the B spline
	  Point2D.Float p(int i, float t, Point2D.Float[] pts) {
	    float px=0;
	    float py=0;
	    for (int j = -2; j<=1; j++){
	      px += b(j,t)*pts[i+j].x;
	      py += b(j,t)*pts[i+j].y;
	    }
	    return new Point2D.Float((int)Math.round(px),(int)Math.round(py));
	  }
	  public int proteinColor(int i, int opacity)
	  {
		  if(Main1.lighter)
				return Main1.blendColor(parent.color(255),parent.color(proteinColorInvert(i, opacity)), Main1.SUBTRACT);
			else return proteinColorInvert(i, opacity);
	  }
		public int proteinColorInvert(int i, int opacity)
		{
			int j = i%8 + 1;
			switch (j) { 
			case 1: return parent.color(255,0,0, opacity);
			case 2: return  parent.color(0,0,255, opacity);
			case 3: return  parent.color(0,255,0, opacity);
			case 4: return  parent.color(255,255,0, opacity);
			case 5: return  parent.color(0,128,255, opacity);
			case 6: return  parent.color(255,0,255, opacity);
			case 7: return  parent.color(0,255,255, opacity);
			case 8: return  parent.color(255,128,0, opacity);
			default: return parent.color(128,0);
			}			
		}	

}
